home *** CD-ROM | disk | FTP | other *** search
- ; SETUP is a memory-resident program that sends control codes to an
- ; Epson-compatible printer. After SETUP is installed, it may be invoked
- ; at any time by pressing the CTRL and the right-SHIFT keys simultaneuosly.
- ; This causes a window to pop up, inviting the user to press a choice
- ; of function keys to send codes to the printer. The window is deactivated
- ; when the ESC key is pressed.
-
- JMP INITIALIZE ; goto initialization routine
-
- DB '(C) Copyright 1986, Ziff-Davis Publishing Company ',01A
-
- KEYBOARD_INT DD 0:(09 * 4)
- MACHINE_ID DD 0F000:0FFFE
- CURSOR_MODE DD 040:060
-
- COLUMN_COUNT DW ? ; width of window in columns
- CURSOR_TYPE DW ? ; cursor scan line definition
- WINDOW_ACTIVE? DB 0 ; indicates if printer window is already active
- DISPLAY_MODE DW ? ; current crt display mode
- PAGE_NUMBER DW ? ; current displayed page
- ATTRIBUTE1 DB 4FH ; window attribute bytes
- ATTRIBUTE2 DB 70H
-
- DISPLAY_TABLE DB 2DH,29H ; display re-enable values for modes 2 and 3
- VIDEO DW 0B800,0B900 ; starting addresses of video memory for CGA
- DW 0BA00,0BB00
-
- MONO_VIDEO DW 0B000H ; video segment address for
- ; monochrome adapter
-
- OLD_KB_INT DD ? ; storage for old keyboard interrupt vector
-
-
- ; Text of the Printer Setup Menu window.
- ; After initialization, text and attribute bytes are combined and stored
- ; in the WINDOW_IMAGE area, and this area is used to store the contents of
- ; the screen that underlie the window when the window is called up.
-
- WINDOW_SOURCE:
- DB 201, 26 DUP 205 ,187
- DB 186,' PRINTER SETUP MENU ',186
- DB 186,' EPSON RX/FX PRINTERS ',186
- DB 199, 26 DUP 196 ,182
- DB 186,' F1 Compressed Mode ',186
- DB 186,' F2 Expanded Mode ',186
- DB 186,' F3 Emphasized Mode ',186
- DB 186,' F4 Double-Strike Mode ',186
- DB 186,' F5 Elite Mode ',186
- DB 186,' F6 Miniature Mode ',186
- DB 186,' F7 Skip Perforation ',186
- DB 186,' F8 Indent Left Margin ',186
- DB 186,' F9 Reset Top-of-Form ',186
- DB 186,' F10 Reset Print Modes ',186
- DB 186,' ESC Exit ',186
- DB 199, 26 DUP 196 ,182
- DB 186,' Unshifted: Toggle ON ',186
- DB 186,' Shifted: Toggle OFF ',186
- DB 200, 26 DUP 205 ,188
- DB 532 DUP (?)
-
- ; Storage area for the combination of text and attribute bytes that
- ; form the window image.
-
- WINDOW_IMAGE:
- DW 532 DUP ?
-
- ; Control code strings for all of the printer setup options.
-
- CODE_TABLE:
- DB 15,255,14 DUP 0 ; compressed mode on
- DB 27,87,1,255,12 DUP 0 ; expanded mode on
- DB 27,69,255,13 DUP 0 ; emphasized mode on
- DB 27,71,255,13 DUP 0 ; double-strike mode on
- DB 27,77,255,13 DUP 0 ; elite mode on
- DB 15,27,83,0,27,65,6,255,8 DUP 0 ; miniature mode on
- DB 27,78,12,255,12 DUP 0 ; perfskip on
- DB 27,108,10,255,12 DUP 0 ; indent left margin
- DB 27,67,66,255,12 DUP 0 ; reset top-of-form
- DB 18,27,87,0,27,70,27,72,27,80,27,84,27,50,255,0 ; reset print modes
- DB 18,255,14 DUP 0 ; compress off
- DB 27,87,0,255,12 DUP 0 ; expand off
- DB 27,70,255,13 DUP 0 ; emphasize off
- DB 27,72,255,13 DUP 0 ; double-strike off
- DB 27,80,255,13 DUP 0 ; elite off
- DB 18,27,84,27,50,255,10 DUP 0 ; miniature off
- DB 27,79,255,13 DUP 0 ; perfskip off
- DB 27,108,0,255,12 DUP 0 ; indent off
-
-
-
- ; OUR_HANDLER is our replacement for the INT 9 keyboard handler. We save
- ; registers, then call the old keyboard handler. If CTRL+RIGHT_SHIFT is
- ; pressed, we activate our code. Otherwise, we exit as if we were the
- ; old handler.
-
- OUR_HANDLER:
- STI ; enable software interrupts
- PUSH AX,BX,CX,DX,SI,DI ; save all registers
- PUSH DS,ES
- PUSH AX ; save ax for call to old routine
- IN AL,0A0H ; re-enable NMI on PCjr
- POP AX ; restore ax
- PUSHF ; simulate interrupt call to old keyboard routine
- CS CALL OLD_KB_INT ; call old routine
- MOV AH,2 ; check status of the shift keys
- INT 16H
- AND AL,5 ; Ctrl and Rt-Shift depressed?
- CMP AL,5
- JE >L1 ; yes, then skip exit routine
- EXIT: ; common exit point
- POP ES,DS
- POP DI,SI,DX,CX,BX,AX
- IRET ; return from interrupt
-
- ; Execution comes here when the proper key combination, Ctrl/Rt-Shift, is
- ; pressed. First task is to check whether or not the window is already open.
-
- L1:
- MOV DS,ES,CS ; set es and ds to the code segment
- TEST WINDOW_ACTIVE? ; is the window already open?
- JNZ EXIT ; yes, then ignore request
-
- ; Check current video mode. If it's mode 2, 3, or 7, then set the window
- ; status flag, store the mode number and page number, save the cursor type,
- ; and hide the cursor. If any other display mode is active instead, ignore
- ; the request and exit.
-
- MOV AH,15 ; get page and mode numbers
- INT 10H ; al=mode, bh=page
- CMP AL,2 ; is crt now in an acceptable mode?
- JE >L0 ; yes, then continue
- CMP AL,3
- JE >L0
- CMP AL,7
- JE >L0
- JMP EXIT
-
- L0:
- CLD ; all string scanning is forward
- INC WINDOW_ACTIVE? ; store the fact that the window is now active
- MOV AH,0 ; extend the mode number AL to AX
- MOV DISPLAY_MODE,AX ; save the mode number
- PUSH BX
- MOV BL,BH ; save page number for color displays
- MOV BH,0
- MOV PAGE_NUMBER,BX
- POP BX
- MOV AH,3 ; get cursor type
- INT 10H
- MOV CURSOR_TYPE,CX ; save it
- MOV AH,1 ; hide the cursor until later
- MOV CH,20H
- INT 10H ;
-
- ; Preparatory routines are completed. Now open the window by first saving the
- ; contents of video memory beneath the window and then writing the window text
- ; directly to memory.
-
- MOV BX,PAGE_NUMBER ; use BX as index into video segment address table
- CMP DISPLAY_MODE,7 ; manually adjust index for monochrome adapter
- IF E MOV BX,4
- SHL BX,1 ; multiply BX by two since table is made up of words
- MOV AX,VIDEO[BX] ; read segment from table
- CMP DISPLAY_MODE,7 ; skip disable if in mode 7
- MOV DS,AX ; DS set to video memory
- IF NE CALL VIDEO_DISABLE ; turn display off for snow-free writing
- MOV DI,WINDOW_SOURCE ; set DI to buffer area to save screen contents
- MOV CX,28 BY 19 ; define window dimensions and location
- MOV DX,2 BY 26
- CALL VIDEO_TO_MEM ; then transfer screen contents to buffer
- MOV ES,DS ; set ES to video memory
- MOV DS,CS ; reset DS to code segment
- LEA SI,WINDOW_IMAGE ; point SI to window image
- MOV CX,28 BY 19 ; define window region
- MOV DX,2 BY 26
- CALL MEM_TO_VIDEO ; and write the window to the display
- CMP DISPLAY_MODE,7 ; skip enable if in mode 7
- IF NE CALL VIDEO_ENABLE ; re-enable the video display
- JMP SHORT NEXT_KEY
-
-
- ; ESC_SEEN is jumped to when the ESC key is pressed. The window is refilled
- ; with its original contents, the cursor is restored, and control is handed
- ; back to the application program.
-
- ESC_SEEN:
- CMP DISPLAY_MODE,7 ; are we in monochrome mode?
- IF NE CALL VIDEO_DISABLE ; if not then turn off the display
- MOV SI,WINDOW_SOURCE ; point SI to the buffer area
- MOV CX,28 BY 19 ; define the window
- MOV DX,2 BY 26
- CALL MEM_TO_VIDEO ; write the buffer contents to the display
- CMP DISPLAY_MODE,7 ; are we in monochrome mode?
- IF NE CALL VIDEO_ENABLE ; if not then turn display back on
- MOV AH,1 ; restore cursor
- MOV CX,CURSOR_TYPE
- INT 10H
- MOV WINDOW_ACTIVE?,0 ; the window is no longer active
- JMP EXIT ; exit back to the interrupted user program
-
-
-
- ; NEXT_KEY is the main loop for the interactive portion of our handler. We
- ; intercept all keystrokes while our window is open, and act on them.
- ; This interactive mode is terminated when the ESC key is seen.
-
- BEEP_KEY: ; jump here if an illegal key is seen
- CALL BEEP ; beep and wait for another keypress
- NEXT_KEY:
- MOV AH,0 ; BIOS function code for GET_KEY
- INT 16H ; fetch a keystroke from the BIOS
- CMP AL,27 ; is it the ESC key?
- JE ESC_SEEN ; jump if it is, to exit our interactive mode
- CMP AL,0 ; is it an extended code?
- JNE BEEP_KEY ; error if not
- MOV AL,AH ; move the extended code into AL, for examination
- CMP AL,59 ; less than F1?
- JB BEEP_KEY ; yes, then don't accept it
- CMP AL,91 ; greater than Shft-F8?
- JA BEEP_KEY ; yes, then don't accept it
- CMP AL,68 ; between F1 and F10?
- JBE UNSHIFTED ; yes
- CMP AL,84 ; between Shft-F1 and Shft-F9?
- JAE SHIFTED ; yes
- JMP BEEP_KEY ; if all tests failed, then keypress was illegal
-
- ; If a legal function key was pressed, its scan code is translated here to the
- ; starting address of the string of bytes to be sent to the printer. The
- ; string is then sent to LPT1: provided it's powered on and on-line.
-
- SHIFTED:
- SUB AL,15 ; adjustment for shifted function keys
- UNSHIFTED:
- SUB AL,59 ; adjustment for unshifted function keys
- MOV AH,0
- MOV CL,4 ; multiply ax by 16
- SHL AX,CL
- ADD AX,CODE_TABLE ; convert ax to full offset address
- MOV SI,AX ; and transfer it to si
- CALL LPT1_ERROR? ; check for printer ready
- JNZ BEEP_KEY ; beep if printer not ready
- MOV BL,255 ; specify delimiter for call to LPRINTZ
- CALL LPRINTZ ; send control code string to printer
- JMP NEXT_KEY ; return for another keypress
-
-
-
- ; VIDEO_ENABLE and VIDEO_DISABLE manipulate bit 3 of port 3D8h, the CGA Mode
- ; Control Register, to temporarily turn the display on or off. Since these
- ; routines write directly to hardware, they have no effect on other video
- ; adapters.
-
- VIDEO_DISABLE:
- MOV DX,03DA ; read CGA status port
- L1:
- IN AL,DX ; wait for vertical retrace to occur
- TEST AL,8 ; is bit 3 set?
- JE L1 ; no, wait until it is
- MOV DX,03D8 ; now disable the display
- MOV AL,025 ; by clearing bit 3 of the Mode Control Register
- OUT DX,AL
- RET
-
- VIDEO_ENABLE:
- MOV DX,03D8 ; CGA Mode Control Register
- MOV BX,DISPLAY_MODE ; get value to re-enable display
- MOV AL,DISPLAY_TABLE[BX-2]
- OUT DX,AL ; and send it to the port
- RET
-
-
-
- ; VIDEO_TO_MEM copies a window (size CH columns by CL lines) from row DH,
- ; column DL of the video segment DS, to a memory buffer at ES:DI.
-
- VIDEO_TO_MEM:
- MOV AL,CH ; store number of columns
- MOV AH,0
- MOV COLUMN_COUNT,AX
- MOV CH,0 ; CX = number of lines
- PUSH DI ; save DI
- CALL VIDEO_OFFSET ; get cell address of first character
- MOV SI,DI ; put it in SI
- POP DI ; restore DI
- L1:
- PUSH SI,CX ; save next line pointer and line count
- MOV CX,COLUMN_COUNT ; load the number of columns in the line
- REP MOVSW ; transfer one line
- POP CX,SI ; restore saved registers
- ADD SI,160 ; set si for next line address
- LOOP L1 ; loop until all lines are done
- RET
-
-
-
- ; MEM_TO_VIDEO writes a window (size CH columns by CL lines), from memory at
- ; DS:SI to the video segment ES, row DH, column DL.
-
- MEM_TO_VIDEO:
- MOV AL,CH ; save number of columns
- MOV AH,0
- MOV COLUMN_COUNT,AX
- MOV CH,0 ; cx = number of lines
- CALL VIDEO_OFFSET ; get offset into video memory
- L1:
- PUSH DI,CX ; save video starting address and line count
- MOV CX,COLUMN_COUNT ; load the number of columns in the line
- REP MOVSW ; transfer one line
- POP CX,DI ; restore registers
- ADD DI,160 ; set di for next display line
- LOOP L1 ; loop until done
- RET
-
-
-
- ; VIDEO_OFFSET sets DI to the offset within the video memory segment of row
- ; DH (0-24), column DL (0-79).
-
- VIDEO_OFFSET:
- MOV AL,160
- MUL DH ; row * 160
- SHL DL,1 ; column * 2
- MOV DH,0 ; byte to word
- ADD AX,DX ; (row *160)+(column*2)
- MOV DI,AX ; set offset in di
- RET
-
-
- ; LPRINTZ routine sends a string of bytes, delimited by BL, from DS:SI to
- ; LPT1: thru INT 17h.
-
- L1:
- MOV DX,0 ; printer no. 0 (LPT1:)
- MOV AH,0
- INT 17H ; send byte to printer
- LPRINTZ:
- LODSB ; get one byte
- CMP AL,BL ; is it the delimiter?
- JNE L1 ; loop if not, to output the byte
- RET
-
-
- ; LPT1_ERROR? checks the current status of printer LPT1:. If it's either
- ; powered off or off-line, then we return NZ to signal an error condition.
- ; If LPT1 is ready, we return Z.
-
- LPT1_ERROR?:
- MOV DX,0 ; printer no. 0
- MOV AH,2 ; use ROM BIOS 'get status' function
- INT 17H ; status is returned in AH
- TEST AH,8 ; test bit 3, I/O error indicator
- RET ; Z means ready, NZ means error
-
-
- ; BEEP uses the 8253 timer chip to emit a short beep thru the PC's speaker.
-
- BEEP:
- MOV AL,182 ; notify 8253 that frequency data is coming
- OUT 67,AL
- MOV AL,0 ; send frequency (776.8 Hz)
- OUT 66,AL
- MOV AL,6
- OUT 66,AL
- IN AL,97 ; activate speaker
- OR AL,3
- OUT 97,AL
- MOV CX,6000H ; time delay for sound duration
- L1:
- LOOP L1
- IN AL,97 ; deactivate speaker
- AND AL,NOT 3
- OUT 97,AL
- RET
-
-
-
- ; Initialization routine sets up the window image in the WINDOW_IMAGE area,
- ; resets the CURSOR_MODE word if this is a PCjr, and saves and replaces the
- ; old keyboard interrupt vector.
-
- INITIALIZE:
-
- ; Initialize the window text area by combining the text data with the attribute
- ; bytes and placing the conglomeration in the WINDOW_IMAGE area.
-
- CLD ; string scanning is forward
- MOV AH,15 ; check the current video mode
- INT 10H
- CMP AL,7 ; if it's mode 7, then replace the attribute
- JNE >L0 ; bytes with ones appropriate for mono adapter
- MOV ATTRIBUTE1,70H
- MOV ATTRIBUTE2,07H
- L0: ; now combine the text and attribute bytes
- LEA SI,WINDOW_SOURCE ; point SI to table of text
- LEA DI,WINDOW_IMAGE ; point DI to the storage area
- MOV CX,112 ; create first four lines by combining text with
- MOV AL,ATTRIBUTE1 ; ATTRIBUTE1 (112 words)
- L1:
- MOVSB ; text byte
- STOSB ; attribute byte
- LOOP L1 ; loop until all 112 words are done
- MOV CX,11 ; now do the next 11 lines
- L2:
- PUSH CX ; first attribute in each line is ATTRIBUTE1
- MOVSB
- STOSB
- MOV CX,26 ; next 26 attributes are ATTRIBUTE2
- MOV AL,ATTRIBUTE2
- L3:
- MOVSB
- STOSB
- LOOP L3
- MOVSB
- MOV AL,ATTRIBUTE1 ; and the last in each line is ATTRIBUTE1
- STOSB
- POP CX
- LOOP L2 ; loop until all 11 lines are done
- MOV CX,112 ; create the last four lines just like the first four
- L4:
- MOVSB
- STOSB
- LOOP L4
-
- ; Check the machine ID byte in ROM and if this is a PCjr, then reset the
- ; cursor and correct the CURSOR_MODE word at 0040:0060.
-
- LES DI,MACHINE_ID ; point to the identification byte for this machine
- MOV AL,0FD ; load the ID to the PCJr
- SCASB ; is this a PCJr?
- JNE >L5 ; no, then skip this routine
- LES DI,CURSOR_MODE ; point to the BIOS's cursor mode indicator
- MOV AX,0607 ; load our new value for the indicator
- STOSW ; store the new value
- XCHG CX,AX ; swap the value into CX, for a BIOS call
- MOV AH,1 ; then physically reset the cursor
- INT 10H
-
- ; Now save the old keyboard interrupt vector and replace it with the new one.
-
- L5:
- LDS SI,KEYBOARD_INT ; point DS:SI to INT 9 in the vector table
- MOV DI,OFFSET OLD_KB_INT ; point ES:DI to our storage for old INT 9 vector
- MOV ES,CS
- CLI ; disable all interrupts but NMI
- MOV AX,OUR_HANDLER ; point to our new handler
- XCHG AX,[SI] ; store new handler offset and fetch the old one
- STOSW ; store the old handler offset
- MOV AX,CS ; point to this code segment
- XCHG AX,[SI+2] ; store new segment and fetch the old one
- STOSW ; store the old handler segment
- STI ; re-enable interrupts
- MOV DX,INITIALIZE ; point dx to end of resident section
- INT 27H ; terminate-but-stay-resident
-